package jtracking_server;

import jtracking_both.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.swing.JOptionPane;
import org.apache.log4j.*;
/**
 * Organisiert die Verbindung zur Datenbank
 *
 */
// <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
// #[regen=yes,id=DCE.88FE5392-F6C4-0E8F-DA12-E497BFD9AD14]
// </editor-fold> 
public class DBManager {
    //Datenbankname: golofni
    //Benutzername: infolog
    //Pwd: golofni
    private String user = "infolog"; //Username
    private String password = "golofni"; //Password
    private String database = "infolog"; //Name der Datenbank
    private String logTabelle= "log";
    //Spalten: PID, User, Zeit, Raum, Einheit
    private String adminTabelle= "Admins";
    //Spalten: User, Password
    Connection con;
    Statement stmt;
    ResultSet rs;
    private HashSet<Datenpaket> datenpakete;
    private final Logger logger = Logger.getLogger(this.getClass());
    /**
     * speichert alle Computer. wird nur erzeugt, wenn eine GUI eine anfrage stellt.
     * wird aus Speichergründen geleert und entfernt, sobald die GUI geschlossen wird.
     */
    private ArrayList<Computer> alleComputer;

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.4634DC6A-EA67-5ED7-4B55-D09813D25461]
    // </editor-fold> 
    protected DBManager () {
        try
        {
            Class.forName("com.mysql.jdbc.Driver");
        }
        catch(ClassNotFoundException mysql_err)
        {
            logger.error("mySQL-Treiber konnte nicht geladen werden" , mysql_err);
            System.exit(-1);
        }
        int i =0;
        for(; i <= 4; i++)
        {
            try
            {
                con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", user, password);
                stmt = con.createStatement();
                i = 6;
            }
            catch (SQLException e)
            {
                logger.error("Fehler beim Verbinden mit mySQL-Server");
            }
        }
        if(i == 5){
            logger.error("Konnte nicht mit Datenbank verbinden. Programm wird beendet");
            System.exit(-1);
        }

        //variablen initialisieren
        datenpakete = new HashSet<Datenpaket>();
        alleComputer = new ArrayList<Computer>();

        //TODO checken, ob Tabellen vorhanden und evtl. erstellen.
        ResultSet result;
        try
        {
            String query4 = "";
            result = stmt.executeQuery(query4);
        }
        catch(SQLException e)
        {

        }

        //liest datenpaket aus der sql tabelle aus
        try
        {
            String query = "SELECT * FROM "+database+"."+logTabelle+";";
            ResultSet resu;
            resu = stmt.executeQuery(query);
            while (resu.next() == true)
            {
                Datenpaket d = new Datenpaket(resu.getString("User"),resu.getString("Einheit"),
                        resu.getString("Raum"),resu.getTimestamp("Zeit"),null);
                datenpakete.add(d);
            }
        }
        catch(SQLException e)
        {
            e.printStackTrace();
        }

        //Verbindung mit SQL herstellen
        
    }



    //TODO: alle paar tage/wochen die alten pakete aus alleDatenpakete löschen, nur auf abfrage einlesen


    /**
     * trägt ein empfangenes Paket in die Datenbank ein
     * zusätzlich auch in datenpakete
     * @param paket
     * @return ob erfolgreich
     */
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.1C1EB4F9-4420-2821-2EBD-FF17898AB19D]
    // </editor-fold> 
    protected boolean paketEintragen (Datenpaket paket) {
        try
        {
            logger.debug("Trage neues Paket ein: "+paket.toString());
            datenpakete.add(paket);

            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            String update = "INSERT INTO "+database+"."+logTabelle+" (User, Zeit, Raum, Einheit)" + " VALUES ('"
                    + paket.getUsername() +"', '" + f.format(paket.getDatum())+ "', '" +paket.getRaum()+ "', '" +paket.getHostname()+ "');";
            logger.debug(update);
            stmt.executeUpdate(update);
            paketEinsortieren(paket);
            return true;
        }
        catch(SQLException e)
        {
            logger.error("Paket konnte nicht Eingetragen werden! "+e.getLocalizedMessage(),e);

            return false;
        }
        
        
    }

    boolean schonComputerSortiert=false;
    /**
     * Gibt alle Computer zurück
     * @return alle Computer in der Datenbank
     */
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.CCA6FEDA-A76F-F685-B045-157039E8E9C7]
    // </editor-fold> 
    protected ArrayList<Computer> getAlleComputer ()
    {
        //wenn die variable alleComputer schon gefüllt ist, diese zurückgeben
        if(alleComputer.size() != 0  && schonComputerSortiert)
        {
            return alleComputer;
        } else {
            alleComputer.clear();
            for (Datenpaket datenpaket : datenpakete) 
            {
                paketEinsortieren(datenpaket);
            }
            // gibt alleComputer zurück
            schonComputerSortiert=true;
            return alleComputer;
        }


    }
    private void paketEinsortieren(Datenpaket paket)
    {
        boolean eingetragen=false;
                for(Computer c:alleComputer)
                {
                    if(c.getName().equals(paket.getHostname()))
                    {
                        c.addDatenpaket(paket);
                        eingetragen=true;
                        break;
                    }
                }
                if(!eingetragen){
                    HashSet<Datenpaket> da=new HashSet<Datenpaket>();
                    da.add(paket);
                    alleComputer.add(new Computer(paket.getHostname(),0,da));
                }
        schonComputerSortiert=true;
    }

    /**
     * prüft ob ein Benutzername und Passwort richtig sind.
     * @param user
     * @param password
     * @return
     */
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.E5BC0D3F-93E8-3F4F-59C6-1FCBB4E2418C]
    // </editor-fold> 
    protected boolean checkAuth (String user, String passwort)
    {

        try {

        String query2 = "SELECT User, Password FROM adminTabelle WHERE User = '"+user+"' AND password = '"+passwort+"';";
        ResultSet res = stmt.executeQuery(query2);
        boolean passwdRichtig=false;
        while((!passwdRichtig)&&res.next())
        {
            if(res.getString("username").equals(user))
            {
                if(res.getString("password").equals(hash(passwort)))
                {
                   passwdRichtig=true;
                }
        }
        return passwdRichtig;
        }
        }
        catch (SQLException sql)
        {
            //fehler was soll ich tun
            JOptionPane.showMessageDialog(Main.main.gui, "please try again.");
        }
        
        
        return false;
    }

    public String hash(String pwd)
    {
        try {
            /* Berechnung */
            MessageDigest md5 = MessageDigest.getInstance("SHA-256"); //wenn das nicht geht, dann md5!
            md5.reset();
            md5.update(pwd.getBytes());
            byte[] result = md5.digest();
            /* Ausgabe */
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < result.length; i++) {
                hexString.append(Integer.toHexString(0xFF & result[i]));
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * fügt der Datenbank einen Neuen Administrator hinzu.
     * @param user
     * @param password
     */
    protected void addAuth (String user, String passwort)
    {


        int res = 0;
        try
        {
            String query = "SELECT User FROM "+database+"."+adminTabelle+" WHERE User = "+ user +"";
            res = stmt.executeUpdate(query);
        }
        catch(SQLException e)
        {

        }
        if( res < 1)
        {
            try
            {
                String update = "INSERT INTO " + database + "." + adminTabelle + " VALUES ('" + user + "', '" + hash(passwort) +  "');";
                stmt.executeUpdate(update);
            }
            catch(SQLException e)
            {

            }
        }
        else
        {
           logger.error("Neuer User konnte nicht erstellt werden oder ist bereits vorhanden!");
        }

    }

    /**
     * löscht einen Administrator aus der Datenbank
     * gibt booolean zurück, ob der user gelöscht wurde/vorhanden war
     * @param user der zu löschende benutzer
     * @return ob erfolgreich
     */
    protected boolean deleteAuth(String user)
    {
        int res ;
        String update= "DELETE FROM "+database+"."+adminTabelle+" WHERE user = '"+user+"';";
        try
        {
            res= stmt.executeUpdate(update);
        }
        catch(SQLException e)
        {
            res=-1;
            logger.error("User konnte nicht gelöscht werden, Fehler beim Verbinden mit der Datenbank",e);
        }
        if(res==1)
        {
            logger.info("User wurde gelöscht.");
            return true;
        }
        else
        {
            logger.error("User konnte nicht gelöscht werden!");
            return false;

        }
    }

    /**
     * liest alle Datenpakete aus der Datenbank, wenn nicht schon eingelesen
     * @return
     */
    protected HashSet<Datenpaket> getDatenpakete ()
    {
        return datenpakete;
    }

    /**
     * wird von der GUI aufgerufen, wenn diese geschlossen wird.
     * gibt Speicherplatz von alleComputer frei.
     */
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.FD8B0BC2-3DA5-F93D-6B63-3C6986C0F9B4]
    // </editor-fold> 
    protected void guiGeschlossen () 
    {
        for(Computer c:alleComputer)
        {
            c.clearDatenpakete();
        }
        //alleComputer leeren
        alleComputer.clear();
        //GarbageCollection anwerfen
        logger.debug("guiGeschlossen wurde aufgerufen, alleComputer wurde geleert.");
        System.gc();
    }
    
}

